package com.kupdater.util;

import com.sun.org.apache.bcel.internal.generic.*;
import com.sun.org.apache.bcel.internal.Constants;
import com.sun.org.apache.bcel.internal.classfile.Field;
import com.sun.org.apache.bcel.internal.classfile.Method;
import com.kupdater.transform.Transformer;
import com.kupdater.transform.ClientTransformer;

import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.LinkedList;

/**
 * Created by IntelliJ IDEA.
 * User: Jan Ove
 * Date: 30.jan.2009
 * Time: 15:15:35
 * To change this template use File | Settings | File Templates.
 */


public class TransformUtils{

    public static List<String[]> output = new LinkedList<String[]>();

    private static ClassGen[] classes;
    private static ClassGen clientCG;

    public static int fieldsShouldHook = 0;
    public static int fieldsHooked = 0;
    public static int classesShouldDefine = 0;
    public static int classesDefined = 0;

    public static void setClasses(ClassGen[] cGs){
        classes = cGs;
        for(ClassGen cG: classes){
            if(cG.getClassName().equals("client"))
                clientCG = cG;
        }
    }


	public static void addInterface(Transformer transformer,ClassGen cG, String name) {
		cG.addInterface(name);
        classesDefined++;
		output.add(new String[]{transformer.getClass().getSimpleName() ,"\t^ " + cG.getClassName() + " implements " + name});
	}

    public static void injectGetMethod(Transformer transformer, ClassGen cG, String className, String fieldName, String name, Type returnType){
        for(ClassGen fieldCG: classes){
            if(fieldCG.getClassName().equals(className)){
                for(Field field: fieldCG.getFields()){
                    if(field.getName().equals(fieldName)){
                        injectGetMethod(transformer, cG, fieldCG, field, name, returnType);
                    }
                }
            }
        }
    }

    public static void injectClientGetMethod(ClassGen cG, Field field, String name, Type returnType){
        injectGetMethod(new ClientTransformer(), cG, cG, field, name, returnType);
    }

    public static void injectClientGetMethod(ClassGen cG, Field field, String name){
        injectGetMethod(new ClientTransformer(), cG, cG, field, name, field.getType());
    }

    public static void injectGetMethod(Transformer transformer, ClassGen cG, Field field, String name){
        injectGetMethod(transformer, cG, cG, field, name, field.getType());
    }

    public static void injectGetMethod(Transformer transformer, ClassGen cG, Field field, String name, Type returnType){
        injectGetMethod(transformer, cG, cG, field, name, returnType);
    }

    public static void injectGetMethod(Transformer transformer, ClassGen cG, ClassGen fieldCG, Field field, String name, Type returnType){
        String access = "";
        {
            if(field.isPublic())
                access += "public ";
            else if(field.isPrivate())
                access += "private ";
            else if(field.isProtected())
                access += "protected ";

            if(field.isStatic())
                access += "static ";
            else if(field.isAbstract())
                access += "abstract ";

            if(field.isFinal())
                access += "final ";
        }
        output.add(new String[]{transformer.getClass().getSimpleName() ,"\t- "+ cG.getClassName() + "." + name + "() returns " + access + returnType.toString() + " " + fieldCG.getClassName() +
                "." + field.getName()});

        ConstantPoolGen cp = cG.getConstantPool();
		InstructionList iList = new InstructionList();
		MethodGen method = new MethodGen(Constants.ACC_PUBLIC,
				returnType, Type.NO_ARGS, new String[] {}, name,
				cG.getClassName(), iList, cp);
		InstructionFactory iFact = new InstructionFactory(cG, cp);
		Instruction pushThis = new ALOAD(0);
		Instruction get = null;
        if(field.isStatic())
            get = iFact.createFieldAccess(fieldCG.getClassName(), field.getName(), field.getType(), Constants.GETSTATIC);
        else
            get = iFact.createFieldAccess(fieldCG.getClassName(), field.getName(), field.getType(), Constants.GETFIELD);
		Instruction returner = iFact.createReturn(returnType);
		iList.append(pushThis);
		iList.append(get);
		iList.append(returner);
		method.setMaxStack();
		method.setMaxLocals();

		cG.addMethod(method.getMethod());
        fieldsHooked++;
    }

    public static Field getFieldByName(ClassGen cG, String name) {
		for(Field field : cG.getFields()) {
			if(field.getName().equals(name)) {
				return field;
			}
		}
		return null;
	}

}
